// 交换两个节点
function swap(A, i, j) {
  let temp = A[i];
  A[i] = A[j];
  A[j] = temp;
}
// 将 i 结点以下的堆整理为大顶堆，注意这一步实现的基础实际上是：
// 假设 结点 i 以下的子堆已经是一个大顶堆，shiftDown函数实现的
// 功能是实际上是：找到 结点 i 在包括结点 i 的堆中的正确位置。后面
// 将写一个 for 循环，从第一个非叶子结点开始，对每一个非叶子结点
// 都执行 shiftDown操作，所以就满足了结点 i 以下的子堆已经是一大
//顶堆
function shiftDown(A, i, length) {
  let temp = A[i]; // 当前父节点
  // j<length 的目的是对结点 i 以下的结点全部做顺序调整
  for (let j = 2 * i + 1; j < length; j = 2 * j + 1) {
    temp = A[i];  // 将 A[i] 取出，整个过程相当于找到 A[i] 应处于的位置
    if (j + 1 < length && A[j] < A[j + 1]) {
      j++;   // 找到两个孩子中较大的一个，再与父节点比较
    }
    if (temp < A[j]) {
      swap(A, i, j) // 如果父节点小于子节点:交换；否则跳出
      i = j;  // 交换后，temp 的下标变为 j
    } else {
      break;
    }
  }
}
// 堆排序
function heapSort(A) {
  // 初始化大顶堆，从第一个非叶子结点开始
  for (let i = Math.floor(A.length / 2 - 1); i >= 0; i--) {
    shiftDown(A, i, A.length);
  }
  // 排序，每一次for循环找出一个当前最大值，数组长度减一
  for (let i = Math.floor(A.length - 1); i > 0; i--) {
    swap(A, 0, i); // 根节点与最后一个节点交换
    shiftDown(A, 0, i); // 从根节点开始调整，并且最后一个结点已经为当
    // 前最大值，不需要再参与比较，所以第三个参数
    // 为 i，即比较到最后一个结点前一个即可
  }
  return A
}

const arr = [2, 1, 10, 8, 5, 4, 7.01, 3.3, 3, 9, 6, 0, -1, -2, 2 * 1, 3 * -1, 1 - 5, 2.13, 2.12]
console.log(heapSort(arr));


// 首先要学习
// ** 二叉树
// * 树
// 有很多种, 每个节点最多只能有两个子节点的叫二叉树  二叉树的子节点分为左节点和右节点
// * 满二叉树
// 二叉树的所有叶子节点都在最后一层, 并且结点总数 = 2 ^ n - 1, n为层数, 则我们称之为满二叉树
// * 完全二叉树  --因为连续所以可以用数组来表示 
// 二叉树除开最后一层，其他层结点数都达到最大，最后一层的所有结点都集中在左边（左边结点排列满的情况下，右边才能缺失结点）。



// * 堆是一个完全二叉树。 分为大顶堆，小顶堆
// 完全二叉树： 二叉树除开最后一层，其他层结点数都达到最大，最后一层的所有结点都集中在左边（左边结点排列满的情况下，右边才能缺失结点）。
// 大顶堆：根结点为最大值，每个结点的值大于或等于其孩子结点的值。
// 小顶堆：根结点为最小值，每个结点的值小于或等于其孩子结点的值。

// 堆排序的时间等于建堆和进行堆调整的时间之和
// 创建最大堆 最大堆调整
// * ===> 请参考 https://www.cnblogs.com/harrymore/p/9121886.html
// * Heap - Sort先调用Build - Max - Heap将数组改造为最大堆
// * 然后将堆顶和堆底元素交换，之后将底部上升，最后重新调用Max - Heapify保持最大堆性质。
// * 由于堆顶元素必然是堆中最大的元素，所以一次操作之后，堆中存在的最大元素被分离出堆，重复n - 1次之后，数组排列完毕。
// * 如果是从小到大排序，用大顶堆；从大到小排序，用小顶堆

// ** 应用示例
// 操作系统动态选择优先级最高的任务执行。
// 静态问题中，在N个元素中选出前M名，使用排序的复杂度：O(NlogN) ，使用优先队列的复杂度: O(NlogM) 。

// ! 支持负数和浮点数

// 不稳定排序